package com.eugeneMa.controller;

import com.eugeneMa.entity.Result;
import com.eugeneMa.entity.UserInfo;
import com.eugeneMa.enumEntity.ErrorMsg;
import com.eugeneMa.service.inter.LoginService;
import com.eugeneMa.util.AuthUtil;
import com.eugeneMa.util.CookieUtil;
import com.eugeneMa.util.StringUtil;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;


/**
 * 登录控制器
 *
 * @author Eugenema
 * @date 2021/10/26 21:29
 */
@Controller
public class LoginController {
    /** 日志 */
    private static Logger logger = Logger.getLogger(LoginController.class);

    /** 登录业务层 */
    @Autowired
    private LoginService loginService;

    /** 本网站地址 */
    @Value("${selfWebUri}")
    private String selfWebUri;

    /** 验证码有效期：15秒，单位毫秒 */
    private static Integer authCodeValidityTime = 15000;

    /**
     * 跳转学习铃页面
     *
     * @author Eugenema
     * @date 2022/1/15 17:23
     **/
    @RequestMapping("/")
    public void toHome(HttpServletRequest request, HttpServletResponse response) {
        try {
            request.getRequestDispatcher("/learnBell/toHomePage").forward(request,response);
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return;
    }


    /**
     * 跳转登录界面
     *
     * @author Eugenema
     * @date 2022/1/15 17:26
     *
     **/
    @RequestMapping("/toLoginPage")
    public String toLoginPage(HttpServletRequest request, HttpServletResponse response) {
        return "/WEB-INF/jsp/login.jsp";
    }

    /**
     * 登录
     *
     * @author Eugenema
     * @date 2022/2/7 10:56
     *
     * @param loginParam 登录参数（用户名、密码、验证码）
     *
     * @return 封装结果集
     **/
    @RequestMapping("/login")
    @ResponseBody
    public Result login(HttpServletRequest request, HttpServletResponse response,
                        @RequestBody Map<String, String> loginParam) {
        /** 会话 */
        HttpSession session = request.getSession();
        try {
            if (loginParam == null) {
                return new Result(false, null, ErrorMsg.PARAM_NULL);
            }

            /** 用户名 */
            String userName = loginParam.get("userName");
            /** 密码 */
            String userPassword = loginParam.get("userPassword");
            /** 验证码 */
            String authCode = loginParam.get("authCode");

            //用户名和密码不能为空
            if (StringUtil.isEmpty(userName) || StringUtil.isEmpty(userPassword)) {
                return new Result(false, null, ErrorMsg.USERNAME_PASSWORD_ERROR);
            }
            //验证码不能为空，且输入正确
            if (!checkAuthCode(authCode, session)) {
                return new Result(false, null, ErrorMsg.AUTHCODE_ERROR);
            }

            //校验用户名和密码
            Result loginResult = loginService.login(userName, userPassword);
            if (loginResult.getFlag()) {
                UserInfo userInfo = (UserInfo)loginResult.getData();
                //创建用户登录信息
                HashMap<String, Object> loginInfo = new HashMap<>(2);
                loginInfo.put("userId", userInfo.getId());
                loginInfo.put("userName", userInfo.getUserName());
                //生成JWT
                String jwt = AuthUtil.createJWT(loginInfo);
                if (jwt == null) {
                    return new Result(false, null, ErrorMsg.SYSTEM_ERROR);
                }

                //存入session，以第三部分作为key，其余部分作为value
                String[] jwtSplit = jwt.split("\\.");
                session.setAttribute(jwtSplit[2], jwtSplit[0] + "." + jwtSplit[1]);

                //将JWT第三部分存入Cookie；不设置过期时间；访问路径为网站下的所有路径
                CookieUtil.addCookie(response, "loginInfo", jwtSplit[2], selfWebUri, -1);
                return new Result(true, null, null);
            }
            return loginResult;
        } catch (Exception e) {
            logger.error("登录异常！", e);
        } finally {
            //无论登录成功与否，均需清空验证码
            session.removeAttribute("authCode");
            session.removeAttribute("lastAuthCodeTime");
        }
        return new Result(false, null, ErrorMsg.SYSTEM_ERROR);
    }

    /**
     * 登出
     *
     * @author Eugenema
     * @date 2022/2/24 20:17
     *
     *
     **/
    @RequestMapping("/logout")
    public String logout(HttpServletRequest request, HttpServletResponse response) {
        /** 会话域 */
        HttpSession session = request.getSession();
        //获取cookie
        String loginInfo = CookieUtil.getCookieValue(request, "loginInfo");
        logger.info("【" + request.getAttribute("userName") + "】用户退出登录！");
        if (!StringUtil.isEmpty(loginInfo)) {
            //删除会话域数据
            session.removeAttribute(loginInfo);
            //删除登录cookie
            CookieUtil.deleteCookie(response, "loginInfo", selfWebUri);
        }
        //跳转登录界面
        return "/WEB-INF/jsp/login.jsp";
    }

    /**
     * 注册
     *
     * @author Eugenema
     * @date 2022/2/27 17:15
     *
     * @param registerParam 注册参数
     *
     * @return 注册结果
     **/
    @RequestMapping("/register")
    @ResponseBody
    public Result register(HttpServletRequest request, @RequestBody Map<String, String> registerParam) {
        HttpSession session = request.getSession();
        try{
            if (registerParam == null) {
                return new Result(false, null, ErrorMsg.PARAM_NULL);
            }

            /** 用户名 */
            String userName = registerParam.get("userName");
            /** 密码 */
            String userPassword = registerParam.get("userPassword");
            /** 确认密码 */
            String affirmPassword = registerParam.get("affirmPassword");
            /** 验证码 */
            String authCode = registerParam.get("authCode");

            //用户名、密码、确认密码不能为空
            if (StringUtil.isEmpty(userName) || StringUtil.isEmpty(userPassword) || StringUtil.isEmpty(affirmPassword)) {
                return new Result(false, null, ErrorMsg.PARAM_ERROR);
            }
            //验证码不能为空，且输入正确
            if (!checkAuthCode(authCode, session)) {
                return new Result(false, null, ErrorMsg.AUTHCODE_ERROR);
            }
            //用户名长度最多为20字符
            if (userName.length() > UserInfo.userNameLength) {
                return new Result(false, null, ErrorMsg.USERNAME_LENGTH);
            }
            return loginService.register(userName, userPassword);
        } catch (Exception e) {
            logger.error("注册异常！", e);
        } finally {
            //无论注册成功与否，均需清空验证码
            session.removeAttribute("authCode");
            session.removeAttribute("lastAuthCodeTime");
        }
        return new Result(false, null, ErrorMsg.SYSTEM_ERROR);
    }

    /**
     * 获取验证码，将验证码放入会话域
     *
     * @author Eugenema
     * @date 2022/2/12 21:45
     *
     **/
    @RequestMapping("/getAuthCode")
    public void getAuthCode(HttpServletRequest request, HttpServletResponse response) {
        try {
            /** 会话域 */
            HttpSession session = request.getSession();

            //检查是否已有验证码 或 是否距离上次获取验证码超过15秒
            //若未超过15秒，则重绘已有的验证码，不会重新获取
            Object lastAuthCodeTime = session.getAttribute("lastAuthCodeTime");
            if (lastAuthCodeTime != null) {
                long lastTime = (long) lastAuthCodeTime;
                if (System.currentTimeMillis() - lastTime < authCodeValidityTime) {
                    String authCode = (String)session.getAttribute("authCode");
                    AuthUtil.getAuthCode(response.getOutputStream(), authCode);
                    return;
                }
            }

            //获取验证码
            String authCode = AuthUtil.getAuthCode(response.getOutputStream(), null);
            //将验证码存入会话域
            session.setAttribute("authCode", authCode);
            session.setAttribute("lastAuthCodeTime", System.currentTimeMillis());
        } catch (Exception e) {
            logger.error("获取验证码异常！", e);
        }
    }

    /**
     * 与会话域中的验证码进行校验
     *
     * @author Eugenema
     * @date 2022/2/27 17:19
     *
     * @param authCode 用户输入的验证码
     * @param session 会话
     *
     * @return 验证结果
     **/
    public boolean checkAuthCode(String authCode, HttpSession session) {
        //会话域的验证码
        Object authCodeObject = session.getAttribute("authCode");

        //验证码不能为空
        if (authCodeObject == null || StringUtil.isEmpty(authCode)) {
            return false;
        } else {
            //验证码需相等，不区分大小写
            String authCodeString = (String)authCodeObject;
            if (!authCode.equalsIgnoreCase(authCodeString)) {
                return false;
            }
        }
        return true;
    }
}
